﻿Public MustInherit Class TextBoxBase : Inherits BaseControl

	Protected TextInfo As StructTextInfo
	Public CarretOn As Boolean
	Public WithEvents Timer As New Timer
	Property AllowOnlyNumeric() As Boolean
	Property UseEnterAsTab() As Boolean = True

	MustOverride Property Value() As Object
	MustOverride ReadOnly Property IsEmpty() As Boolean

	Sub New()
		BorderStyle = Windows.Forms.BorderStyle.None
		Padding = New Padding(2)
		DoubleBuffered = True
		Timer.Interval = 300
		Cursor = Cursors.IBeam
	End Sub

	Property SpecialField() As String

	Property [Default] As Object

	Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, keyData As System.Windows.Forms.Keys) As Boolean
		If keyData = Keys.Escape Then IsDirty = False
		If keyData = Keys.Enter AndAlso UseEnterAsTab Then
			SendKeys.Send("{TAB}")
			Return True
		End If
		Return MyBase.ProcessCmdKey(msg, keyData)
	End Function

	Property SmartFormatting As Boolean

	Public Overrides Sub Reset()
		MyBase.Reset()
		Value = [Default]
	End Sub

	Protected Overrides Sub OnKeyDown(e As System.Windows.Forms.KeyEventArgs)
		MyBase.OnKeyDown(e)
		If e.Handled Then Return
		If e.Control And e.KeyCode = Keys.A Then
			SelectAll()
			e.Handled = True
		End If
		Select Case If(e.Shift, Keys.Shift, 0) + If(e.Control, Keys.Control, 0) + e.KeyCode
			Case Keys.Left
				ClearSelection()
				If IntSelectionStart > 0 Then IntSelectionStart -= 1
				e.Handled = True
			Case Keys.Right
				ClearSelection()
				If IntSelectionStart < Len(Text) Then IntSelectionStart += 1
				e.Handled = True
			Case Keys.Delete
				If IntSelectionLength = 0 Then IntSelectionLength += 1
				InsertText("")
				IntSelectionLength = 0
				e.Handled = True
			Case Keys.Right Or Keys.Shift
				If IntSelectionStart + IntSelectionLength < Len(Text) Then IntSelectionLength += 1
				e.Handled = True
			Case Keys.Left Or Keys.Shift
				If IntSelectionStart + IntSelectionLength > 0 Then IntSelectionLength -= 1
				e.Handled = True
			Case Keys.Home
				IntSelectionLength = 0
				IntSelectionStart = 0
				e.Handled = True
			Case Keys.End
				IntSelectionLength = 0
				IntSelectionStart = Len(Text)
				e.Handled = True
			Case Keys.Shift Or Keys.Home
				IntSelectionStart = IntSelectionStart + IntSelectionLength
				IntSelectionLength = -IntSelectionStart
				e.Handled = True
			Case Keys.Shift Or Keys.End
				IntSelectionStart = IntSelectionStart + IntSelectionLength
				IntSelectionLength = Len(Text) - IntSelectionStart
				e.Handled = True
			Case Keys.Control Or Keys.Left
				Dim WordFound As Boolean = False
				ClearSelection()
				Do
					If IntSelectionStart = 0 Then Exit Do
					If Not WordFound Then WordFound = IsWordPart(Mid(Text, IntSelectionStart, 1))
					If WordFound Then If Not IsWordPart(Mid(Text, IntSelectionStart, 1)) Then Exit Do
					IntSelectionStart -= 1
				Loop
				e.Handled = True
			Case Keys.Shift Or Keys.Control Or Keys.Left
				Dim WordFound As Boolean = False
				Do
					If IntSelectionStart + IntSelectionLength = 0 Then Exit Do
					If Not WordFound Then WordFound = IsWordPart(Mid(Text, IntSelectionStart + IntSelectionLength, 1))
					If WordFound Then If Not IsWordPart(Mid(Text, IntSelectionStart + IntSelectionLength, 1)) Then Exit Do
					IntSelectionLength -= 1
				Loop
				e.Handled = True
			Case Keys.Control Or Keys.Right
				Dim SpaceFound As Boolean = False
				ClearSelection()
				Do
					If IntSelectionStart >= Len(Text) Then Exit Do
					If Not SpaceFound Then SpaceFound = Not IsWordPart(Mid(Text, IntSelectionStart + 1, 1))
					If SpaceFound Then If IsWordPart(Mid(Text, IntSelectionStart + 1, 1)) Then Exit Do
					IntSelectionStart += 1
				Loop
				e.Handled = True
			Case Keys.Shift Or Keys.Control Or Keys.Right
				Dim SpaceFound As Boolean = False
				Do
					If IntSelectionStart + IntSelectionLength >= Len(Text) Then Exit Do
					If Not SpaceFound Then SpaceFound = Not IsWordPart(Mid(Text, IntSelectionStart + IntSelectionLength + 1, 1))
					If SpaceFound Then If IsWordPart(Mid(Text, IntSelectionStart + IntSelectionLength + 1, 1)) Then Exit Do
					IntSelectionLength += 1
				Loop
				e.Handled = True
			Case Keys.Control Or Keys.C, Keys.Control Or Keys.Insert
				Copy()
			Case Keys.Control Or Keys.X, Keys.Shift Or Keys.Delete
				Cut()
			Case Keys.Control Or Keys.V, Keys.Shift Or Keys.Insert
				Paste()
		End Select
	End Sub

	Protected Overrides Function IsInputKey(keyData As System.Windows.Forms.Keys) As Boolean
		If (keyData And Keys.Shift) > 0 Then keyData -= Keys.Shift
		Select Case keyData
			Case Keys.Left, Keys.Right, Keys.Up, Keys.Down : Return True
			Case Keys.Home, Keys.End : Return True
		End Select
		Return MyBase.IsInputKey(keyData)
	End Function

	Protected Overrides Sub OnKeyPress(e As System.Windows.Forms.KeyPressEventArgs)
		MyBase.OnKeyPress(e)
		If e.Handled Then Return
		If e.KeyChar = Chr(8) Then
			If IntSelectionStart = 0 Then Exit Sub
			If IntSelectionLength = 0 Then
				IntSelectionStart -= 1
				IntSelectionLength = +1
			End If
			InsertText("")
		ElseIf e.KeyChar > Chr(31) Then
			InsertText(e.KeyChar)
		End If
	End Sub

	Protected Overrides Sub OnLostFocus(e As System.EventArgs)
		MyBase.OnLostFocus(e)
		Timer.Stop()
		CarretOn = False
		Invalidate()
	End Sub

	Protected Overrides Sub OnMouseDown(e As System.Windows.Forms.MouseEventArgs)
		If ShowDropDownButton Then
			If Not Focused Then Focus()
			If DropDownRect.Contains(e.Location) Then
				OnDropDownButtonClicked(e)
				Return
			End If
		End If
		If ShowUpDownButtons Then
			If Not Focused Then Focus()
			If UpDownRect.Contains(e.Location) Then
				OnUpDownButtonClicked(e, If(e.Y < Height / 2, 1, -1))
				Return
			End If
		End If
		MyBase.OnMouseDown(e)
		IntSelectionLength = 0
		IntSelectionStart = HitTest(e.Location)
	End Sub

	Protected Overrides Sub OnMouseMove(e As System.Windows.Forms.MouseEventArgs)
		MyBase.OnMouseMove(e)
		If ShowDropDownButton Then
			If DropDownRect.Contains(e.Location) Then
				If MouseOnDropDown Then Return
				MouseOnDropDown = True
			Else
				MouseOnDropDown = False
			End If
		End If
		If ShowUpDownButtons Then
			If UpDownRect.Contains(e.Location) Then
				If MouseOnUpDown Then Return
				MouseOnUpDown = True
			Else
				MouseOnUpDown = False
			End If
		End If
		Cursor = If(MouseOnDropDown Or MouseOnUpDown, Cursors.Default, If(ShowCursor, Cursors.IBeam, Cursors.Default))
		If e.Button = Windows.Forms.MouseButtons.Left Then
			IntSelectionLength = HitTest(e.Location) - IntSelectionStart
		End If
	End Sub

	Protected Overrides Sub OnMouseLeave(e As System.EventArgs)
		MyBase.OnMouseLeave(e)
		MouseOnDropDown = False
		MouseOnUpDown = False
	End Sub

	Property ShowCursor As Boolean = True

	Protected Overrides Sub OnPaintBackground(e As System.Windows.Forms.PaintEventArgs)
		Dim R = ClientRectangle
		e.Graphics.FillRectangle(New SolidBrush(BackColor), R)
		'e.Graphics.FillRectangle(New SolidBrush(Color.Red), R)
	End Sub

	ReadOnly Property TextRectangle As Rectangle
		Get
			Return New Rectangle(Padding.Left, Padding.Top, Width - Padding.Horizontal, Height - Padding.Vertical)
		End Get
	End Property

	Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
		Dim Text As String = Me.Text
		If PasswordChar <> "" Then Text = StrDup(Len(Text), PasswordChar)
		Dim R = TextRectangle
		Dim Flags As TextFormatFlags = TextFormatFlags.NoPadding
		If TextAlign <> HorizontalAlignment.Left Then
			Dim l = Measure(e.Graphics, Text, Font, R.Size, Flags).Width
			If TextAlign = HorizontalAlignment.Right Then
				R.Offset(R.Width - l, 0)
			ElseIf TextAlign = HorizontalAlignment.Center Then
				R.Offset(Int((R.Width - l) / 2), 0)
			End If
			R.Width = l
		End If
		If ShowCursor Then
			If Focused Then
				Dim a(1) As Integer
				Dim ss As Integer = IntSelectionStart + If(IntSelectionLength < 0, IntSelectionLength, 0)
				Dim sl As Integer = Math.Abs(IntSelectionLength)
				a(0) = Measure(e.Graphics, Mid(Text, 1, ss), Font, R.Size, Flags).Width
				a(1) = Measure(e.Graphics, Mid(Text, 1, ss + sl), Font, R.Size, Flags).Width
				Dim R1 = New Rectangle(R.Left + a(0), R.Top, a(1) - a(0), R.Height)
				R1.Inflate(0, 1)
				e.Graphics.FillRectangle(SystemColors.Highlight.Opacity(128).Brush, R1)
				Dim x = If(IntSelectionLength < 0, a(0), a(1)) + R.Left
				If CarretOn And Timer.Enabled Then OnDrawCursor(e.Graphics, x, R1)
			End If
			If Hint <> "" Then
				DrawSmartText(e.Graphics, Hint, Font, R, Color.Gray, Color.Transparent, Flags)
			End If
		End If
		Dim t = Text
		Dim col = Color.Black
		If Not Enabled OrElse [ReadOnly] Then col = Themes.Current.LabelColor
		If ShowCursor Then
			If Focused AndAlso Hint = Text Then t = Mid(t, 1, SelectionStart)
		End If
		DrawSmartText(e.Graphics, t, Font, R, col, Color.Transparent, Flags)
		If Me.Text = "" AndAlso DefaultText <> "" Then
			DrawSmartText(e.Graphics, DefaultText, Font, R, SystemColors.GrayText, Color.Transparent, Flags)
		End If
		e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
		e.Graphics.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
		OnPaintButtons(e)
	End Sub

	Overridable Sub OnPaintButtons(e As PaintEventArgs)
		If ShowDropDownButton Then
			Dim R = DropDownRect
			'e.Graphics.FillRectangle(BackColor.Brush, R)
			R.Inflate(-1, -1)
			Dim col = Mix(Themes.Current.FormColor, Color.Black, If(MouseOnDropDown, 20, 0))
			'e.Graphics.FillRoundRect(R, col.Brush, 3)
			Renderer.PaintButton(e.Graphics, R, Nothing, False, MouseOnDropDown, False, True, True, 3)
			R.Offset(1, 0)
			TextRenderer.DrawText(e.Graphics, "6", New Font("marlett", 8), R, Color.Black.Mix(Themes.Current.FormColor, If(Enabled, 0, 50)), Color.Transparent, TextFormatFlags.HorizontalCenter + TextFormatFlags.VerticalCenter)
		End If
		If ShowUpDownButtons Then
			Dim R = UpDownRect
			R.Inflate(-1, -1)
			Dim col = Mix(Themes.Current.FormColor, Color.Black, If(MouseOnUpDown, 20, 0))
			e.Graphics.FillRoundRect(R, col.Brush, 3)
			R.Offset(1, 0)
			R.Offset(0, -3)
			TextRenderer.DrawText(e.Graphics, "t", New Font("marlett", 8), R, Color.Black.Mix(Themes.Current.FormColor, If(Enabled, 0, 50)), Color.Transparent, TextFormatFlags.HorizontalCenter + TextFormatFlags.VerticalCenter)
			R.Offset(0, 6)
			TextRenderer.DrawText(e.Graphics, "u", New Font("marlett", 8), R, Color.Black.Mix(Themes.Current.FormColor, If(Enabled, 0, 50)), Color.Transparent, TextFormatFlags.HorizontalCenter + TextFormatFlags.VerticalCenter)
		End If
	End Sub
#Region " Dropdown Button "

	Dim DropDownRect As Rectangle
	Dim _ShowDropDownButton As Boolean
	Public Property ShowDropDownButton As Boolean
		Get
			Return _ShowDropDownButton
		End Get
		Set(value As Boolean)
			_ShowDropDownButton = value
			OnSizeChanged(Nothing)
		End Set
	End Property

	Dim UpDownRect As Rectangle
	Dim _ShowUpDownButtons As Boolean
	Public Property ShowUpDownButtons As Boolean
		Get
			Return _ShowUpDownButtons
		End Get
		Set(value As Boolean)
			_ShowUpDownButtons = value
			OnSizeChanged(Nothing)
		End Set
	End Property

	Dim _MouseOnDropDown As Boolean
	Private Property MouseOnDropDown As Boolean
		Get
			Return _MouseOnDropDown
		End Get
		Set(value As Boolean)
			_MouseOnDropDown = value
			Invalidate()
		End Set
	End Property

	Dim _MouseOnUpDown As Boolean
	Private Property MouseOnUpDown As Boolean
		Get
			Return _MouseOnUpDown
		End Get
		Set(value As Boolean)
			_MouseOnUpDown = value
			Invalidate()
		End Set
	End Property

#End Region

	Private Sub Timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer.Tick
		CarretOn = Not CarretOn
		Invalidate()
	End Sub

	Property AutoCompleteCustomSource As AutoCompleteStringCollection

	Property AutoCompleteMode As AutoCompleteMode

	Property AutoCompleteSource As AutoCompleteSource

	Public Overrides Property MinimumSize As System.Drawing.Size
		Get
			Return New Size(1, ControlHeight)
		End Get
		Set(value As System.Drawing.Size)
			MyBase.MinimumSize = value
		End Set
	End Property

	Public Overrides Property MaximumSize As System.Drawing.Size
		Get
			Return New Size(10000, ControlHeight)
		End Get
		Set(value As System.Drawing.Size)
			MyBase.MaximumSize = value
		End Set
	End Property

	Protected Overrides Sub OnSizeChanged(e As System.EventArgs)
		MyBase.OnSizeChanged(e)
		Dim R = ClientRectangle
		If ShowDropDownButton Then
			DropDownRect = New Rectangle(R.Right - 15, 0, 15, Height)
			R.Width -= 15
		Else
			DropDownRect = Rectangle.Empty
		End If
		If ShowUpDownButtons Then
			UpDownRect = New Rectangle(R.Right - 15, 0, 15, Height)
			R.Width -= 15
		Else
			UpDownRect = Rectangle.Empty
		End If
	End Sub

	Dim InitialText As String
	Property IsDirty() As Boolean
		Get
			Return Text <> InitialText
		End Get
		Set(Value As Boolean)
			If Not Value Then InitialText = Text
		End Set
	End Property


	Protected Overrides Sub OnEnabledChanged(e As System.EventArgs)
		MyBase.OnEnabledChanged(e)
		SetBackColor()
	End Sub

	Protected Overrides Sub OnGotFocus(e As System.EventArgs)
		MyBase.OnGotFocus(e)
		InitialText = Text
		If AutoSelectAll Then SelectAll()
		Timer.Start()
		CarretOn = True
		Invalidate()
	End Sub

	Overridable Sub OnDropDownButtonClicked(e As MouseEventArgs)
	End Sub

	Overridable Sub OnUpDownButtonClicked(e As MouseEventArgs, inc As Integer)
	End Sub

	Property SelectionStart() As Integer
		Get
			Return If(IntSelectionLength < 0, IntSelectionStart + IntSelectionLength, IntSelectionStart)
		End Get
		Set(ByVal Value As Integer)
			IntSelectionStart = Value
		End Set
	End Property

	Property SelectionLength() As Integer
		Get
			Return Math.Abs(IntSelectionLength)
		End Get
		Set(ByVal Value As Integer)
			IntSelectionLength = Value
		End Set
	End Property


	Dim m_IntSelectionStart As Integer
	Private Property IntSelectionStart() As Integer
		Get
			Return m_IntSelectionStart
		End Get
		Set(ByVal Value As Integer)
			m_IntSelectionStart = Value
			CarretOn = True
			Invalidate()
		End Set
	End Property

	Dim m_IntSelectionLength As Integer
	Private Property IntSelectionLength() As Integer
		Get
			Return m_IntSelectionLength
		End Get
		Set(ByVal Value As Integer)
			m_IntSelectionLength = Value
			Invalidate()
		End Set
	End Property

	Sub ClearSelection()
		IntSelectionStart += IntSelectionLength
		IntSelectionLength = 0
	End Sub

	Sub Cut()
		If SelectedText = "" Then Return
		Copy()
		InsertText("")
	End Sub

	Sub Copy()
		If PasswordChar <> "" Then Return
		If SelectedText = "" Then Return
		Clipboard.SetText(SelectedText)
	End Sub

	Sub Paste()
		If Clipboard.GetText = "" Then Return
		InsertText(Clipboard.GetText)
	End Sub
	Function IsWordPart(ByVal c As Char) As Boolean
		If c >= "0" And c <= "9" Then Return True
		Return UCase(c) <> LCase(c)
	End Function

	Private Sub InsertText(ByVal S As String)
		If [ReadOnly] Then Return
		If MaxLength > 0 AndAlso Len(Text) - SelectionLength + Len(S) > MaxLength Then Return
		Dim WillHint = S > ""
		If IntSelectionLength < 0 Then
			IntSelectionStart += IntSelectionLength
			IntSelectionLength = -IntSelectionLength
		End If
		Dim t = IntSelectionStart
		Dim Value = Mid(Text, 1, IntSelectionStart) & S & Mid(Text, IntSelectionStart + IntSelectionLength + 1)
		If t <> IntSelectionStart Then Return
		IntSelectionLength = 0
		IntSelectionStart = IntSelectionStart + Len(S)
		Hint = ""
		If WillHint AndAlso Not AutoCompleteCustomSource Is Nothing AndAlso Not Value = "" Then
			For Each Item As String In AutoCompleteCustomSource
				If Mid(Item.ToLower, 1, Value.Length) = Value.ToLower Then
					Text = Item
					Value = Item
					Hint = Item
					IntSelectionLength = -(Value.Length - SelectionStart)
					IntSelectionStart = Value.Length
					Return
				End If
			Next
		End If
		Text = Value
	End Sub

	Dim m_Text As String
	Overrides Property Text() As String
		Get
			Return m_Text
		End Get
		Set(ByVal Value As String)
			If m_Text = Value Then Return
			m_Text = Value
			Hint = ""
			OnTextChanged(Nothing)
			Invalidate()
		End Set
	End Property

	Sub SelectAll()
		IntSelectionStart = 0
		IntSelectionLength = Len(Text)
	End Sub

	Shadows Sub [Select](Start As Integer, Length As Integer)
		SelectionStart = Start
		SelectionLength = Length
	End Sub

	Dim m_AutoSelectAll As Boolean = True
	Property AutoSelectAll() As Boolean
		Get
			Return m_AutoSelectAll
		End Get
		Set(ByVal Value As Boolean)
			m_AutoSelectAll = Value
		End Set
	End Property

	Dim m_MaxLength As Integer = 0
	Property MaxLength() As Integer
		Get
			Return m_MaxLength
		End Get
		Set(ByVal Value As Integer)
			m_MaxLength = Value
		End Set
	End Property

	Dim m_ReadOnly As Boolean
	Shadows Property [ReadOnly]() As Boolean
		Get
			Return m_ReadOnly
		End Get
		Set(ByVal Value As Boolean)
			m_ReadOnly = Value
		End Set
	End Property

	Property SelectedText() As String
		Get
			Return Mid(Text, SelectionStart + 1, SelectionLength)
		End Get
		Set(ByVal Value As String)
			Mid(Text, SelectionStart + 1, SelectionLength) = Value
			SelectionStart += Len(Value)
			SelectionLength = 0
		End Set
	End Property

	Dim m_MultiLine As Boolean
	Property [MultiLine]() As Boolean
		Get
			Return m_MultiLine
		End Get
		Set(ByVal Value As Boolean)
			m_MultiLine = Value
		End Set
	End Property

	Dim m_TextAlign As System.Windows.Forms.HorizontalAlignment
	Property TextAlign() As System.Windows.Forms.HorizontalAlignment
		Get
			Return m_TextAlign
		End Get
		Set(ByVal Value As System.Windows.Forms.HorizontalAlignment)
			m_TextAlign = Value
		End Set
	End Property

	Property PasswordChar As String

	Dim _Hint As String
	Property Hint As String
		Get
			Return _Hint
		End Get
		Set(Value As String)
			If Value = Hint Then Return
			_Hint = Value
			Invalidate()
		End Set
	End Property

	Dim m_DefaultText As String = ""
	Property DefaultText() As String
		Get
			Return m_DefaultText
		End Get
		Set(ByVal Value As String)
			m_DefaultText = Value
			Invalidate()
		End Set
	End Property

	Private Function Measure(g As Graphics, Text As String, Font As Drawing.Font, Size As Size, Flags As TextFormatFlags) As Size
		If SmartFormatting Then Text = Text.Replace("_", "0")
		Return TextRenderer.MeasureText(g, Text, Font, Size, Flags)
	End Function

	Private Sub DrawSmartText(g As Graphics, Text As String, Font As Drawing.Font, R As Rectangle, TextColor As Color, BackColor As Color, Flags As TextFormatFlags)
		If Text Is Nothing Then Return
		If SmartFormatting Then
			Dim Items = Text.Split("_")
			For i = 0 To Items.Count - 1
				If i > 0 Then
					TextRenderer.DrawText(g, "•", Font, R, TextColor.Lighter(75), BackColor, Flags)
					R.Offset(Measure(g, "0", Font, New Size(10000, 10000), Flags).Width, 0)
				End If
				Dim Item = Items(i)
				If Item <> "" Then
					TextRenderer.DrawText(g, Item, Font, R, TextColor, BackColor, Flags)
					R.Offset(Measure(g, Item, Font, New Size(10000, 10000), Flags).Width, 0)
				End If
			Next
			Return
		End If
		Flags += TextFormatFlags.VerticalCenter
		TextRenderer.DrawText(g, Text, Font, R, TextColor, BackColor, Flags)
	End Sub

	Function HitTest(ByVal P As Point) As Integer
		Dim G As Graphics = CreateGraphics()
		Dim Flags As New TextFormatFlags
		Flags = TextFormatFlags.NoPadding
		Dim R = ClientRectangle
		R.Inflate(-2, -2)
		If P.X < R.Left Then Return 0
		Dim Text = Me.Text
		If PasswordChar <> "" Then Text = StrDup(Len(Text), PasswordChar)
		If TextAlign = HorizontalAlignment.Right Then
			Dim l = Measure(G, Text, Font, R.Size, Flags).Width
			R.Offset(R.Width - l, 0)
			R.Width = l
		ElseIf TextAlign = HorizontalAlignment.Center Then
			Dim l = Measure(G, Text, Font, R.Size, Flags).Width
			R.Offset((R.Width - l) / 2, 0)
			R.Width = l
		End If
		Dim c As Integer = 0
		Dim x(1) As Integer
		If P.X < R.Left Then Return 0
		For i As Integer = 1 To Len(Text)
			x(c) = Measure(G, Mid(Text, 1, i), Font, R.Size, Flags).Width + R.Left
			If x(c) = P.X Then Return i
			If c = 1 Then Return If(Math.Abs(P.X - x(0)) < Math.Abs(P.X - x(1)), i - 1, i)
			If x(c) > P.X Then c += 1
		Next
		Return Len(Text)
	End Function

	Overridable Sub OnDrawCursor(g As Graphics, x As Integer, R As Rectangle)
		g.DrawLine(Pens.Black, x, R.Top, x, R.Bottom - 1)
	End Sub

	Protected Overrides Sub OnTextChanged(e As System.EventArgs)
		MyBase.OnTextChanged(e)
		RaiseEvent TextChanged(Me, e)
	End Sub

	Shadows Event TextChanged(sender As Object, e As EventArgs)

End Class

Public Structure StructTextInfo
	Public Text As String
	Public SelectionStart As Integer
	Public SelectionLength As Integer
End Structure

Public Enum CharacterCasing
	Normal
	Upper
	Lower
	Title
End Enum
